package com.guiji.text2video.fastvideo.service.Impl;

import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.guiji.text2video.common.core.utils.DateUtils;
import com.guiji.text2video.fastvideo.domain.vo.Text2videoJob;
import com.guiji.text2video.fastvideo.domain.vo.Text2videoZipJob;
import com.guiji.text2video.fastvideo.mapper.Text2videoZipJobMapper;
import com.guiji.text2video.fastvideo.service.INLPService;
import com.guiji.text2video.fastvideo.service.IText2videoZipJobService;
import com.guiji.text2video.fastvideo.utils.*;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.Charset;
import java.util.*;

/**
 * @program: text2video
 * @description:
 * @author: gaoX
 * @create: 2021-06-07 15:35
 **/
@Service
public class Text2videoZipJobServiceImpl implements IText2videoZipJobService {

    @Autowired
    private INLPService nLPService;

    private static final Logger logger = LoggerFactory.getLogger(Text2videoZipJobServiceImpl.class);

    @Autowired
    private Text2videoZipJobMapper text2videoZipJobMapper;

    @Autowired
    Text2videoJobServiceImpl text2videoJobServiceImpl;

    private final static int errorLenth = 256;

    @Value("${file-cache.wav-dir}")
    private String wavDir;

    /**
     * 查询【请填写功能名称】
     *
     * @param id 【请填写功能名称】ID
     * @return 【请填写功能名称】
     */
    @Override
    public Text2videoZipJob selectText2videoZipJobById(Long id) {
        return text2videoZipJobMapper.selectText2videoZipJobById(id);
    }

    /**
     * 查询【请填写功能名称】列表
     *
     * @param text2videoZipJob 【请填写功能名称】
     * @return 【请填写功能名称】
     */
    @Override
    public List<Text2videoZipJob> selectText2videoZipJobList(Text2videoZipJob text2videoZipJob) {
        return text2videoZipJobMapper.selectText2videoZipJobList(text2videoZipJob);
    }

    /**
     * 新增【请填写功能名称】
     *
     * @param text2videoZipJob 【请填写功能名称】
     * @return 结果
     */
    @Override
    public int insertText2videoZipJob(Text2videoZipJob text2videoZipJob) {
        text2videoZipJob.setCreateTime(DateUtils.getNowDate());
        return text2videoZipJobMapper.insertText2videoZipJob(text2videoZipJob);
    }

    /**
     * 修改【请填写功能名称】
     *
     * @param text2videoZipJob 【请填写功能名称】
     * @return 结果
     */
    @Override
    public int updateText2videoZipJob(Text2videoZipJob text2videoZipJob) {
        text2videoZipJob.setUpdateTime(DateUtils.getNowDate());
        return text2videoZipJobMapper.updateText2videoZipJob(text2videoZipJob);
    }

    /**
     * 批量删除【请填写功能名称】
     *
     * @param ids 需要删除的【请填写功能名称】ID
     * @return 结果
     */
    @Override
    public int deleteText2videoZipJobByIds(Long[] ids) {
        return text2videoZipJobMapper.deleteText2videoZipJobByIds(ids);
    }

    /**
     * 删除【请填写功能名称】信息
     *
     * @param id 【请填写功能名称】ID
     * @return 结果
     */
    @Override
    public int deleteText2videoZipJobById(Long id) {
        return text2videoZipJobMapper.deleteText2videoZipJobById(id);
    }

    @Override
    public void insertText2videoZipJobByList(List<Text2videoZipJob> listText2videoZipJob) {
        text2videoZipJobMapper.insertText2videoZipJobByList(listText2videoZipJob);
    }

    @Override
    public Map<String, String> updateStat(String zipId) {
        Map<String, String> map = new HashMap<>();
        Map<String, Long> mapInfo = text2videoZipJobMapper.countSFC(zipId);
        Long success = mapInfo.get("success");
        Long fail = mapInfo.get("error");
        Long uncommit =mapInfo.get("uncommit");
        Long running =mapInfo.get("running");
        Long txtSize =running+uncommit+fail+success;

        Text2videoZipJob text2videoZipJob = new Text2videoZipJob();
        text2videoZipJob.setZipId(zipId);
        text2videoZipJob.setComplateSize(String.valueOf(success));
        text2videoZipJob.setErrorSize(String.valueOf(fail));
        text2videoZipJob.setRunningSize(String.valueOf(running));
        text2videoZipJob.setUpdateTime(new Date());
        text2videoZipJobMapper.updateText2videoZipJob(text2videoZipJob);
        map.put("总计文本数量", String.valueOf(txtSize));
        map.put("成功文本数量", String.valueOf(success));
        map.put("正在运行数量", String.valueOf(running));
        map.put("未提交的数量", String.valueOf(uncommit));
        map.put("失败文本数量", String.valueOf(fail));
        map.put("===========", "=============");
        List<Text2videoJob> errorJobs = text2videoJobServiceImpl.selectErrorJobsByZipId(zipId);
        for (Text2videoJob job:errorJobs){
            map.put(job.getTitle(),job.getBackup2());
        }
        return map;
    }

    @Override
    public List<Map<String, String>> selectDownloadUrl(String zipId) {
        return text2videoZipJobMapper.selectDownloadUrl(zipId);
    }

    @Override
    public String multiTaskZip(MultipartFile fileZip, Text2videoJob job) throws Exception {
        String zipId = GeneratID.getZipGeneratID();

        File file = new File(fileZip.getOriginalFilename());
        try {
            FileUtil.writeFromStream(fileZip.getInputStream(), file);
        } catch (Exception e) {
            logger.error(e.toString());
        }

        List<File> res = null;
        try {
            File unzip = ZipUtil.unzip(file, Charset.forName("GBK"));
            res = (List<File>) FileUtils.listFiles(unzip, null, true);
            String txtSize = String.valueOf(res.size());
            Text2videoZipJob text2videoZipJob = new Text2videoZipJob();
            text2videoZipJob.setZipId(zipId);
            text2videoZipJob.setTxtSize(txtSize);
            text2videoZipJob.setIsSuccess(Enums.JobSign.NLP_FAILED.getKey());
            text2videoZipJob.setComplateSize(Enums.JobSign.RUNNING.getKey());
            text2videoZipJob.setErrorSize(Enums.JobSign.RUNNING.getKey());
            text2videoZipJob.setRunningSize(Enums.JobSign.RUNNING.getKey());
            text2videoZipJob.setUncommitSize(Enums.JobSign.RUNNING.getKey());
            text2videoZipJob.setCreateTime(new Date());
            //初始化到zip表
            insertText2videoZipJob(text2videoZipJob);

            List<String> listID = new ArrayList<>();
            for (File f : res) {
                //保证zipid和jobid对应关系
                String jobGeneratID = GeneratID.getJobGeneratIdWithZip(zipId);
                listID.add(jobGeneratID);
            }
            List<File> finalRes = res;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //做校验
                    checkFormat(finalRes, listID, zipId, job);
                    //删除解压出来的文件
                    FileUtil.del(unzip.getAbsolutePath());
                    FileUtil.del(file.getAbsolutePath());
                }
            }).start();

        } catch (Exception e) {
            throw new Exception(Enums.httpCode.ERROR_04.getValue());
        }
        return zipId;
    }

    @Override
    public void checkFormat(List<File> files, List<String> listId, String zipId, Text2videoJob job) {
        for (int i = 0; i < files.size(); i++) {
            File file = files.get(i);
            String title = file.getName().replaceAll(".txt", "");
            StringBuilder sb = new StringBuilder();
            try {
                FileUtil.readUtf8Lines(file).forEach((s) -> {
                    sb.append(s);
                });
            } catch (Exception e) {
                job.setBackup2(Enums.JobSign.CHECk_FAILED.getValue());
                insertJob(title, Enums.JobSign.CHECk_FAILED.getValue(), listId.get(i), Enums.JobSign.CHECk_FAILED.getKey(), zipId, file, job);
                continue;
            }

            String content = sb.toString();
            //0、空指针判断
            if (ObjectUtils.isEmpty(title) || ObjectUtils.isEmpty(content)) {
                insertJob(title, Enums.JobSign.CHECk_FAILED.getValue(), listId.get(i), Enums.JobSign.CHECk_FAILED.getKey(), zipId, file, job);
                continue;
            }
            //1、文件编码为非utf-8
            Charset charset = CharsetUtils.detectCharset(file);
            if (ObjectUtils.isEmpty(charset) || !(charset.equals(CharsetUtil.CHARSET_UTF_8) || charset.equals(CharsetUtil.CHARSET_ISO_8859_1))) {
                job.setBackup2(Enums.JobSign.ENCODE_ERROR.getValue());
                insertJob(title, Enums.JobSign.ENCODE_ERROR.getValue(), listId.get(i), Enums.JobSign.ENCODE_ERROR.getKey(), zipId, file, job);
                continue;
            }
            //2、文件格式验证
            String type = FileTypeUtil.getType(file);
            if (!StrUtil.isEmpty(type) && !"txt".equals(type)) {
                job.setBackup2(Enums.JobSign.TYPE_ERROR.getValue());
                insertJob(title, Enums.JobSign.TYPE_ERROR.getValue(), listId.get(i), Enums.JobSign.TYPE_ERROR.getKey(), zipId, file, job);
                continue;
            }
            //3、文本长度
            if (content.length() > Enums.numSign.contentSize.getKey() || content.length() < 1 || title.length() < 1) {
                job.setBackup2(Enums.JobSign.COUNT_ERROR.getValue());
                insertJob(title, Enums.JobSign.COUNT_ERROR.getValue(), listId.get(i), Enums.JobSign.COUNT_ERROR.getKey(), zipId, file, job);
            } else {
                try {
                    //成功插入
                    insertJob(title, content, listId.get(i), Enums.JobSign.UNCOMMITTED.getKey(), zipId, file, job);
                } catch (Exception e) {
                    job.setBackup2(Enums.JobSign.CHECk_FAILED.getValue());
                    insertJob(title, Enums.JobSign.CHECk_FAILED.getValue(), listId.get(i), Enums.JobSign.CHECk_FAILED.getKey(), zipId, file, job);
                    e.printStackTrace();
                }
            }
        }
    }


    private void insertJob(String title, String content, String jobId, String isSuccess, String zipId, File file, Text2videoJob videoJob) {
        Text2videoJob job = new Text2videoJob();
        job.setTitle(title);
        job.setContent(content);
        job.setJobId(jobId);
        job.setIsSuccess(isSuccess);
        job.setZipId(zipId);
        job.setCreateTime(new Date());
        job.setBackup1(GetLocalIpUtil.getIp());
        job.setBackup2(videoJob.getBackup2());
        job.setTtsSpeaker(videoJob.getTtsSpeaker());
        job.setTtsRate(videoJob.getTtsRate());
        job.setBackup3(videoJob.getBackup3());
        //资源类型
        job.setTtsType(videoJob.getTtsType());
        text2videoJobServiceImpl.insertText2videoJob(job);
        if (file.exists()) {
            file.delete();
        }
    }

    @Override
    public List<File> transferToLocal(MultipartFile[] files) {
        List<File> list = new ArrayList<>();
        for (int i = 0; i < files.length; i++) {
            String filename = files[i].getOriginalFilename();
            File dest = new File(wavDir + filename);
            try {
                if (dest.exists()) {
                    dest.delete();
                }
                new FileWriter(wavDir + filename).writeFromStream(files[i].getInputStream());
                list.add(dest);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return list;
    }

    @Override
    public void muiltyCommit(Text2videoJob text2videoJob) {
        text2videoJob.setIsSuccess(Enums.JobSign.RUNNING.getKey());
        text2videoJob.setBackup1(GetLocalIpUtil.getIp());
        //2,更换不同版本NLP服务，异步任务-线程池
        try {
            nLPService.executeNLPAsync(text2videoJob);
        } catch (InterruptedException e) {
            text2videoJob.setIsSuccess(Enums.JobSign.UNCOMMITTED.getKey());
            text2videoJob.setBackup2(Enums.JobSign.UNCOMMITTED.getValue());
            text2videoJobServiceImpl.updateText2videoJob(text2videoJob);
            e.printStackTrace();
            return;
        }
        //3，响应请求
        text2videoJobServiceImpl.updateText2videoJob(text2videoJob);

    }
    @Override
    public void muiltyNewsCommit(Text2videoJob text2videoJob) {
        try {
            nLPService.executeNLPAsync(text2videoJob);
        } catch (InterruptedException e) {
            text2videoJob.setIsSuccess(Enums.JobSign.UNCOMMITTED.getKey());
            text2videoJob.setBackup2(Enums.JobSign.UNCOMMITTED.getValue());
            text2videoJobServiceImpl.updateText2videoJob(text2videoJob);
            e.printStackTrace();
            return;
        }
    }




    @Override
    public BufferedOutputStream readFileToByteArray(File file, HttpServletResponse response) throws IOException {
        BufferedOutputStream os = new BufferedOutputStream(response.getOutputStream());

        InputStream fis = new BufferedInputStream(new FileInputStream(file));

        byte[] b = new byte[1024];
        while ((fis.read(b)) != -1) {
            os.write(b);
        }
        fis.close();
        return os;
    }

}
